/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package edu.ucuenca.ec.nosql.conexion;

import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.MongoClient;
import com.mongodb.ServerAddress;
import com.mongodb.util.JSON;
import edu.ucuenca.ec.nosql.modelos.Category;
import edu.ucuenca.ec.nosql.modelos.Producto;
import edu.ucuenca.ec.nosql.modelos.Review;
import java.io.IOException;
import java.net.UnknownHostException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 *
 * @author mivkys
 */
public class DriverMongoDB {

    private static DB dB;

    // -------------------------------------------------------------------------
    // PROPIEDAD SET   
    public static void setDB_Mongo(String DataBase) {
        try {
            MongoClient mongoClient = new MongoClient(Arrays.asList(
                    //new ServerAddress("192.168.1.101", 27017),
                    //new ServerAddress("192.168.1.102", 27017),
                    new ServerAddress("localhost", 27017)));
            System.out.println("Si entro");
            dB = mongoClient.getDB("amazondb");/// aki DataBase
            System.out.println("conexion..." + dB);
            //Sesion.setVariable("mongoDB", dB);
            //dB = (DB) Sesion.getVariable("mongoDB");///revisar
        } catch (UnknownHostException ex) {
            System.out.println("Problmeas de conexion con mongodb");
        }
    }

    // -------------------------------------------------------------------------
    // PROPIEDAD GET
    public static DB getDB_Mongo() {
        return dB;
    }

    public static void insert(Producto producto, String nameCollection) throws IOException {
        if (dB == null) {
            System.out.println("conexion no establecida");
            return;
        }
        Gson gson = new Gson();
        String jsonString = gson.toJson(producto);
        DBObject dbObject = (DBObject) JSON.parse(jsonString);
        DBCollection collection = dB.getCollection(nameCollection);
        collection.insert(dbObject);
    }

    public static void update(String nameCollection, String claveSearch, Object valorSearch, String claveUpdate, Object valorUpdate) {
        if (dB == null) {
            System.out.println("conexion no establecida");
            return;
        }
        BasicDBObject findTestItemQuery = new BasicDBObject();
        findTestItemQuery.put(claveSearch, valorSearch);
        DBCursor testItemsCursor = (dB.getCollection(nameCollection)).find(findTestItemQuery);
        if (testItemsCursor.hasNext()) {
            DBObject testCodeItem = testItemsCursor.next();
            testCodeItem.put(claveUpdate, valorUpdate);
            (dB.getCollection(nameCollection)).save(testCodeItem);
        }
    }

    public static void update(String nameCollection, Producto producto) throws IOException {
        if (dB == null) {
            System.out.println("conexion no establecida");
            return;
        }
        remove(nameCollection, producto.getId());
        insert(producto, nameCollection);
    }

    public static void remove(String nameCollection, Object valor) {
        if (dB == null) {
            System.out.println("conexion no establecida");
            return;
        }
        DBObject basicDBObject = new BasicDBObject();
        basicDBObject.put("Id", valor);
        (dB.getCollection(nameCollection)).remove(basicDBObject);
        /**
         * BasicDBObject deleteQuery = new BasicDBObject();
         * deleteQuery.put("priority", "highest"); DBCursor cursor =
         * items.find(deleteQuery); while (cursor.hasNext()) { DBObject item =
         * cursor.next(); items.remove(item); }
         */
    }

    public static Producto findIdProducto(String nameCollection, int valor) {
        List<Producto> productos = find(nameCollection, "Id", (Object) valor);
        return (productos != null) ? productos.get(0) : null;
    }

    public static List<Producto> find(String nameCollection, String clave, Object valor) {
        if (dB == null) {
            System.out.println("conexion no establecida");
            return null;
        }
        List<Producto> productos = new ArrayList<>();
        JsonParser parser = new JsonParser();
        BasicDBObject whereQuery = new BasicDBObject();
        whereQuery.put(clave, valor);
        DBCursor cursor = (dB.getCollection(nameCollection)).find(whereQuery);
        while (cursor.hasNext()) {
            JsonElement datos = parser.parse(cursor.next().toString());
            Producto producto = new Producto();
            dumpJSONElement(datos, "", producto, new Category(), new Review(), '-');
            productos.add(producto);
        }
        return productos;
    }

    public static List<Producto> findLimit(String nameCollection, int limit) {
        if (dB == null) {
            System.out.println("conexion no establecida");
            return null;
        }
        List<Producto> productos = new ArrayList<>();
        JsonParser parser = new JsonParser();
        BasicDBObject fields = new BasicDBObject();
        fields.put("Id", limit);
        DBCursor cursor = (dB.getCollection(nameCollection)).find(fields);
        while (cursor.hasNext()) {
            JsonElement datos = parser.parse(cursor.next().toString());
            Producto producto = new Producto();
            dumpJSONElement(datos, "", producto, new Category(), new Review(), '-');
            productos.add(producto);
        }
        return productos;
    }

    public static List<Producto> findAll(String nameCollection) {
        if (dB == null) {
            System.out.println("conexion no establecida");
            return null;
        }
        List<Producto> productos = new ArrayList<>();
        JsonParser parser = new JsonParser();
        DBCursor dbCursor = (dB.getCollection(nameCollection)).find();
        while (dbCursor.hasNext()) {
            JsonElement datos = parser.parse(dbCursor.next().toString());
            Producto producto = new Producto();
            dumpJSONElement(datos, "", producto, new Category(), new Review(), '-');
            productos.add(producto);
//            Gson gson = new Gson();
//            String jsonString = gson.toJson(producto);
//            System.out.println("JSON: " + jsonString);
        }
        return productos;
    }

    private static void dumpJSONElement(JsonElement elemento, String clave, Producto producto, Category category, Review review, char arrays) {

        if (elemento.isJsonObject()) {
            JsonObject obj = elemento.getAsJsonObject();
            java.util.Set<java.util.Map.Entry<String, JsonElement>> entradas = obj.entrySet();
            java.util.Iterator<java.util.Map.Entry<String, JsonElement>> iter = entradas.iterator();
            while (iter.hasNext()) {
                java.util.Map.Entry<String, JsonElement> entrada = iter.next();
                clave = entrada.getKey();
                if (clave.equalsIgnoreCase("categories")) {
                    arrays = 'c';
                } else {
                    arrays = '-';
                }
                dumpJSONElement(entrada.getValue(), clave, producto, category, review, arrays);
            }

        } else if (elemento.isJsonArray()) {
            JsonArray array = elemento.getAsJsonArray();
            java.util.Iterator<JsonElement> iter = array.iterator();
            while (iter.hasNext()) {
                System.out.println(arrays);
                if (arrays == 'c') {
                    category = new Category();
                }
                JsonElement entrada = iter.next();
                dumpJSONElement(entrada, clave, producto, category, review, arrays);
                if (arrays == 'c') {
                    producto.getCategories().add(category);
                }
            }
        } else if (elemento.isJsonPrimitive()) {
            JsonPrimitive valor = elemento.getAsJsonPrimitive();
            construcionObjeto(valor, clave, producto, category, review);
        } else if (elemento.isJsonNull()) {
            System.out.println("Es NULL");
        } else {
            System.out.println("Es otra cosa");
        }
    }

    private static void construcionObjeto(JsonPrimitive valor, String clave, Producto producto, Category category, Review review) {
        if (clave.equalsIgnoreCase("Id")) {
            producto.setId(valor.getAsInt());
        } else if (clave.equalsIgnoreCase("ASIN")) {
            producto.setASIN(valor.getAsString());
        } else if (clave.equalsIgnoreCase("title")) {
            producto.setTitle(valor.getAsString());
        } else if (clave.equalsIgnoreCase("group")) {
            producto.setGroup(valor.getAsString());
        } else if (clave.equalsIgnoreCase("salesrank")) {
            producto.setSalesrank(valor.getAsInt());
        } else if (clave.equalsIgnoreCase("similars")) {
            producto.getSimilars().add(valor.getAsInt());
        } else if (clave.equalsIgnoreCase("subCategory")) {
            category.getSubCategory().add(valor.getAsString());
        } else if (clave.equalsIgnoreCase("date")) {
            SimpleDateFormat formateador = new SimpleDateFormat("MMM dd, yyyy");
            try {
                review.setDate(formateador.parse(valor.getAsString()));
            } catch (ParseException ex) {
                System.out.println("No es el formato deseado");

            }
        } else if (clave.equalsIgnoreCase("customer")) {
            review.setCustomer(valor.getAsInt());
        } else if (clave.equalsIgnoreCase("rating")) {
            review.setRating(valor.getAsInt());
        } else if (clave.equalsIgnoreCase("votes")) {
            review.setVotes(valor.getAsInt());
        } else if (clave.equalsIgnoreCase("helpful")) {
            review.setHelpful(valor.getAsInt());
            producto.getReviews().add(review);
            review = new Review();
        } else if (clave.equalsIgnoreCase("downloaded")) {
            producto.setDownloaded(valor.getAsInt());
        }

    }
}
